package cn.ncu.wechat.service.impl;

import cn.ncu.wechat.model.Orders;
import cn.ncu.wechat.service.WeChatPayService;
import cn.ncu.wechat.util.WeChatPayUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.springframework.beans.factory.annotation.Value;
import org.apache.hc.core5.ssl.SSLContexts;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.springframework.stereotype.Service;

import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
public class WeChatPayServiceImpl implements WeChatPayService {

    @Value("${wx.app.mchId}")
    private String mchid;

    @Value("${wx.app.appid}")
    private String appId;

    @Value("${wx.app.mchId}")
    private String mchId;

    @Value("${wx.app.apiKey}")
    private String apiKey;

    @Value("${wx.app.notifyUrl}")
    private String notifyUrl;

    @Value("${cn.ncu.signType}")
    private String signType;

    @Value("${wx.app.apiclientUrl}")
    private String apiClient;

    public Map<String, String> createMiniProgramPayRequest(String openId, String body,Orders order) {
        Map<String, String> params = new HashMap<>();
        params.put("appid", appId);
        params.put("mch_id", mchId);
        params.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
        params.put("body", "七和医疗美容-超市");
        params.put("out_trade_no", order.getOrderNo());
        BigDecimal totalFee = order.getAmount().multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP);
        int totalFeeInt = totalFee.intValueExact();
        params.put("total_fee",String.valueOf(totalFeeInt));
        params.put("spbill_create_ip", "120.26.115.63");
        params.put("notify_url", notifyUrl);
        params.put("trade_type", "JSAPI");
        params.put("openid", openId);
        // 生成签名
        String sign = WeChatPayUtil.generateSignature(params, apiKey);
        params.put("sign", sign);
        return params;
    }

    public String requestWeChatPay(Map<String, String> params) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        String xmlParams = xmlMapper.writeValueAsString(params);
        System.out.println("params:"+params);
        System.out.println("xmlParams :"+xmlParams);
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");
        httpPost.setHeader("Content-Type", "application/xml");
        httpPost.setEntity(new StringEntity(xmlParams));

        try (CloseableHttpClient httpClient = HttpClients.createDefault();
             CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return EntityUtils.toString(response.getEntity());
        }
    }

    public Map<String, String> parseWeChatPayResponse(String xmlResponse) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        return xmlMapper.readValue(xmlResponse, Map.class);
    }

    public Map<String, String> createMiniProgramPayment(String openId,Orders order, String body) throws Exception {
        Map<String, String> requestParams = createMiniProgramPayRequest(openId, body, order);
        String xmlResponse = requestWeChatPay(requestParams);
        Map<String, String> responseParams = parseWeChatPayResponse(xmlResponse);

        // 处理响应，返回prepay_id等
        Map<String, String> params = new HashMap<>();
        if (responseParams.get("return_code").equals("SUCCESS")){
            long currentTimeSeconds = System.currentTimeMillis() / 1000;
            // 将秒数转换为字符串
            String timestampString = String.valueOf(currentTimeSeconds);
            params.put("appId",appId);
            params.put("nonceStr",responseParams.get("nonce_str"));
            params.put("package","prepay_id="+responseParams.get("prepay_id"));
            params.put("signType","MD5");
            params.put("timeStamp",timestampString);
            String sign = WeChatPayUtil.generateSignature(params, apiKey);
            params.put("paySign",sign);
        } else params.put("failReason", responseParams.get("return_msg"));
        return params;
    }


    /**
     * 创建退款请求参数
     *
     * @param order       订单信息
     * @return 退款请求参数
     */
    public Map<String, String> createRefundRequest(Orders order) {
        Map<String, String> params = new HashMap<>();
        params.put("appid", appId);
        params.put("mch_id", mchId);
        params.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
        params.put("out_trade_no", order.getOrderNo());
        params.put("out_refund_no", "REFUND_" + order.getOrderNo()); // 退款单号
        BigDecimal totalFee = order.getAmount().multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP);
        int totalFeeInt = totalFee.intValueExact();
        params.put("total_fee", String.valueOf(totalFeeInt));
        BigDecimal refundFee = order.getAmount().multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP);
        int refundFeeInt = refundFee.intValueExact();
        params.put("refund_fee", String.valueOf(refundFeeInt));
        params.put("op_user_id", mchId); // 操作员ID，通常为商户号
        params.put("notify_url", notifyUrl); // 退款结果通知URL

        // 生成签名
        String sign = WeChatPayUtil.generateSignature(params, apiKey);
        params.put("sign", sign);

        return params;
    }


    /**
     * 发送退款请求
     *
     * @param params 退款请求参数
     * @return 微信支付返回的XML响应
     * @throws Exception
     */
    public String requestRefund(Map<String, String> params) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        String xmlParams = xmlMapper.writeValueAsString(params);

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
        httpPost.setHeader("Content-Type", "application/xml");
        httpPost.setEntity(new StringEntity(xmlParams));

        // 使用配置了证书的HTTP客户端发送请求
        try (CloseableHttpClient httpClient = createHttpClientWithCert();
             CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return EntityUtils.toString(response.getEntity());
        }
    }

    /**
     * 解析微信支付退款响应
     *
     * @param xmlResponse 微信支付返回的XML响应
     * @return 解析后的Map
     * @throws Exception
     */
    public Map<String, String> parseRefundResponse(String xmlResponse) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        return xmlMapper.readValue(xmlResponse, Map.class);
    }

    /**
     * 执行退款操作
     *
     * @param order        订单信息
     * @return 退款结果
     * @throws Exception
     */
    public Map<String, String> refund(Orders order) throws Exception {
        Map<String, String> requestParams = createRefundRequest(order);
        String xmlResponse = requestRefund(requestParams);
        Map<String, String> responseParams = parseRefundResponse(xmlResponse);

        // 验证签名
        if (WeChatPayUtil.isSignatureValid(responseParams, apiKey)) {
            if ("SUCCESS".equals(responseParams.get("return_code"))){
                // 退款成功
                return responseParams;
            } else {
                // 退款失败
                throw new RuntimeException("退款失败: " + responseParams.get("return_msg"));
            }
        } else {
            throw new RuntimeException("签名验证失败");
        }
    }

    private CloseableHttpClient createHttpClientWithCert() throws Exception {
        // 加载证书文件
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (InputStream inputStream = new FileInputStream(apiClient)) {
            keyStore.load(inputStream, mchId.toCharArray());
        }
        // 初始化SSLContext
        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, mchId.toCharArray())
                .build();
        // 创建SSLConnectionSocketFactory
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
        // 创建连接管理器并配置SSL
        PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
                .setSSLSocketFactory(sslSocketFactory)
                .build();
        // 创建HTTP客户端
        return HttpClients.custom()
                .setConnectionManager(connectionManager)
                .build();
    }

}